﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Reactive.Disposables;
using LinqToOwin;

namespace Owin
{
  public static class AppBuilderExtensions
  {
    public static IDisposable UseLinqToOwin(this IAppBuilder app, IEnumerable<Func<LinqToOwinHost, IObservable<object>>> queries)
    {
      Contract.Requires(app != null);
      Contract.Requires(queries != null);
      Contract.Ensures(Contract.Result<IDisposable>() != null);

      return app.UseLinqToOwin(context => from query in queries
                                          select query(context));
    }

    public static IDisposable UseLinqToOwin(this IAppBuilder app, Func<LinqToOwinHost, IEnumerable<IObservable<object>>> queryFactory)
    {
      Contract.Requires(app != null);
      Contract.Requires(queryFactory != null);
      Contract.Ensures(Contract.Result<IDisposable>() != null);

      var disposables = new CompositeDisposable();

      app.Use<LinqToOwinMiddleware>(disposables, queryFactory);

      return disposables;
    }

    public static IDisposable UseLinqToOwin(this IAppBuilder app, Func<IAppBuilder, LinqToOwinHost, IEnumerable<IObservable<object>>> queryFactory)
    {
      Contract.Requires(app != null);
      Contract.Requires(queryFactory != null);
      Contract.Ensures(Contract.Result<IDisposable>() != null);

      var disposables = new CompositeDisposable();

      app.Use<LinqToOwinMiddleware>(disposables, (Func<LinqToOwinHost, IEnumerable<IObservable<object>>>)(host => queryFactory(app, host)));

      return disposables;
    }
  }
}